Deterministic, safe evaluation and analysis of infix math/logic expression
strings supplied by a caller with a variable map — e.g. "price * quantity * (1 + tax)" or "age >= 18 && country == 'US'". Built for the Axiom
marketplace (handle christiangeorgelucas).
Wraps expr-eval-fork (MIT,
zero runtime dependencies) — the actively-maintained, security-patched fork
of expr-eval that fixes two 2025 RCE CVEs present in the original library
(prototype-pollution via member access, CVE-2025-13204; and unrestricted
function invocation from a caller-supplied context, CVE-2025-12735). This
package depends on the fork, not the original, deliberately.
Every node in this package is a live, auto-scaling API endpoint on the Axiom marketplace — call it from an AI agent or your own code, with nothing to self-host.
📦 See it on the marketplace: https://dev.axiomide.com/marketplace/christiangeorgelucas/expression-tools@0.1.0
Hook it up to an AI agent (MCP). Add Axiom's hosted MCP server to any MCP client and every node becomes a typed tool your agent can call — search the catalog, inspect a schema, and invoke it directly.
# Claude Code
claude mcp add --transport http axiom https://api.axiomide.com/mcp \
--header "Authorization: Bearer $AXIOM_API_KEY"Claude Desktop, Cursor, or any config-based client:
{
"mcpServers": {
"axiom": {
"type": "http",
"url": "https://api.axiomide.com/mcp",
"headers": { "Authorization": "Bearer YOUR_AXIOM_API_KEY" }
}
}
}Call it from the CLI.
axiom invoke christiangeorgelucas/expression-tools/Evaluate --input '{ ... }'Call it over HTTP.
curl -X POST https://api.axiomide.com/invocations/v1/nodes/christiangeorgelucas/expression-tools/0.1.0/Evaluate \
-H "Authorization: Bearer $AXIOM_API_KEY" \
-H 'Content-Type: application/json' \
-d '{ ... }'Input/output schema for each node is on the marketplace page above, or via
axiom inspect node christiangeorgelucas/expression-tools/Evaluate.
Install the CLI:
# macOS / Linux — Homebrew
brew install axiomide/tap/axiom
# macOS / Linux — install script
curl -fsSL https://raw.githubusercontent.com/AxiomIDE/axiom-releases/main/install.sh | shWindows: download the windows/amd64 .zip from the
releases page, unzip it,
and put axiom.exe on your PATH.
Then axiom version to verify, axiom login (GitHub or Google) to authenticate,
and create an API key under Console → API Keys. Docs and sign-up at
axiomide.com.
- Evaluate — evaluate an expression against a caller-supplied variable
map, returning a typed result (number, boolean, or string). Covers plain
numeric evaluation (no variables), boolean/comparison/logical evaluation,
and an optional deterministic
result_typecoercion. - Validate — check whether an expression is syntactically well-formed without evaluating it; reports the parser's line/column on a syntax error when the underlying parser supplies one.
- ExtractVariables — list every distinct variable name an expression references, and whether it is constant (references none).
- Substitute — partially evaluate an expression by binding a subset of its variables, returning the reduced expression string and the variables still unbound.
- Parse — parse an expression into its compiled postfix (RPN) token structure without evaluating it, for inspection/rendering/highlighting.
- ListCapabilities — list the deterministic operator/function/constant surface this evaluator exposes.
This is an eval-adjacent domain, hardened deliberately:
- Member access disabled (
allowMemberAccess: false) — the library's own default is actuallytrue; since every variable this package accepts is a flat scalar, dotted access buys a caller nothing, so the whole "reach through an object" attack class is removed outright. - Prototype/constructor access blocked by the fork itself —
__proto__,prototype, andconstructoridentifiers are rejected before evaluation. - Functions are allowlisted by the fork — a caller-supplied variable that happens to be a function is never invoked unless it is a registered/safe function.
randomis removed on every parser instance — the library's one non-deterministic builtin. Every other exposed operator/function/constant is a pure, deterministic math function; there is no clock, network, or filesystem access anywhere in this package.- The
=assignment operator and inline function-definition syntax are disabled (operators: { assignment: false, fndef: false }). Both are enabled by default in the underlying library, and left enabled an expression likeprice = 0; price * quantitysilently overwrites the "variable"pricemid-expression and returns 0 withok: trueinstead of the caller's evidently-intended computation — a wrong, non-obvious answer on a thoroughly realistic input (found by independent review, using this package's own worked pricing example). Disablingassignmentmakes=fail to tokenize at all, so it degrades to a clean parse error instead.ListCapabilitiesfilters its operator lists through the parser's ownisOperatorEnabledrather than just listing table keys, for the same reason: a disabled operator remains a key in the underlying tables and would otherwise still be advertised as supported. - Length and nesting-depth caps run before an expression ever reaches the
parser (2000 chars / 64 levels of
(/[nesting), so a pathological input fails with a structured error instead of a native stack overflow — verified empirically against the installed library (deep nesting throws a rawRangeErroraround depth ~700–1000; the cap sits well below that).
Every node is a pure, stateless, deterministic single-input → single-output transform.
MIT — Copyright (c) 2026 Christian George Lucas. See LICENSE.